package com.ssy.lingxi.member.merchant.serviceimpl.base;

import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.member.MemberStatusEnum;
import com.ssy.lingxi.common.constant.member.MemberTypeEnum;
import com.ssy.lingxi.common.constant.member.RoleTypeEnum;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.Aes128Util;
import com.ssy.lingxi.common.utils.PasswordUtil;
import com.ssy.lingxi.component.redis.service.IRedisUtils;
import com.ssy.lingxi.member.merchant.api.constant.CountryCodeEnum;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.config.ServiceVariable;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.AddMemberBO;
import com.ssy.lingxi.member.merchant.model.bo.ProcessBO;
import com.ssy.lingxi.member.merchant.model.constant.MemberRegisterSourceEnum;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.model.constant.MemberUserAuthTypeEnum;
import com.ssy.lingxi.member.merchant.model.constant.PlatformInnerStatusEnum;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.*;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.CountryCodeVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.MemberConfigGroupVO;
import com.ssy.lingxi.member.merchant.model.vo.login.request.ResetPasswordByEmailCodeVO;
import com.ssy.lingxi.member.merchant.model.vo.login.request.ResetPasswordBySmsCodeVO;
import com.ssy.lingxi.member.merchant.model.vo.login.response.MemberRegisterResultVO;
import com.ssy.lingxi.member.merchant.model.vo.login.response.MemberRegisterTypeMenuVO;
import com.ssy.lingxi.member.merchant.repository.*;
import com.ssy.lingxi.member.merchant.service.base.*;
import com.ssy.lingxi.member.merchant.service.feign.ISmsFeignService;
import com.ssy.lingxi.member.merchant.service.mobile.IBaseMobileService;
import com.ssy.lingxi.member.merchant.utils.MailUtil;
import com.ssy.lingxi.member.merchant.utils.SecurityStringUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 会员注册相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2020-12-03
 */
@Service
public class BaseRegisterServiceImpl implements IBaseRegisterService {
    @Resource
    private IBaseMemberRegisterDetailService baseMemberRegisterDetailService;

    @Resource
    private IBaseMobileService baseMobileService;

    @Resource
    private CountryCodeRepository countryCodeRepository;

    @Resource
    private MemberRepository memberRepository;

    @Resource
    private MemberUserRepository memberUserRepository;

    @Resource
    private MemberTypeRepository memberTypeRepository;

    @Resource
    private MemberBusinessTypeRepository memberBusinessTypeRepository;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private IBasePlatformProcessService basePlatformProcessService;

    @Resource
    private IBaseMemberInnerService memberInnerService;

    @Resource
    private ISmsFeignService smsFeignService;

    @Resource
    private IBaseMemberCacheService memberCacheService;

    @Resource
    private IRedisUtils redisUtils;

    /**
     * 获取国家代码和手机号码位数
     * @return 查询结果
     */
    @Override
    public Wrapper<List<CountryCodeVO>> listCountryCode() {
        return Wrapper.success(countryCodeRepository.findAll(Sort.by("typeEnum").ascending()).stream().map(countryCodeDO -> {
            CountryCodeVO codeVO = new CountryCodeVO();
            codeVO.setCode(countryCodeDO.getCode());
            codeVO.setName(countryCodeDO.getName());
            codeVO.setPhoneLength(countryCodeDO.getPhoneLength());
            return codeVO;
        }).collect(Collectors.toList()));
    }

    /**
     * 检查手机号码是否被注册使用
     *
     * @param phoneVO 手机号码
     * @return 检查结果
     */
    @Override
    public Wrapper<Void> checkPhoneRegistered(PhoneVO phoneVO) {
        MemberUserDO memberUserDO = memberUserRepository.findFirstByPhoneAndRelType(phoneVO.getPhone(), MemberRelationTypeEnum.OTHER.getCode());

        if(memberUserDO != null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_EXISTS);
        }

        return Wrapper.success();
    }

    /**
     * 移动端 - 手机找回密码页面，检查手机号码是否被注册使用
     *
     * @param phoneVO 手机号码
     * @return 检查结果
     */
    @Override
    public Wrapper<Void> checkPhoneExistsByMobile(PhoneVO phoneVO) {
        Wrapper<String> phoneResult = checkCountryPhone(phoneVO.getCountryCode(), phoneVO.getPhone(), false);
        if(phoneResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(phoneResult.getCode(), phoneResult.getMessage());
        }

        MemberUserDO memberUserDO = memberUserRepository.findFirstByPhoneAndRelType(phoneResult.getData(), MemberRelationTypeEnum.OTHER.getCode());

        if(memberUserDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        MemberDO memberDO = memberUserDO.getMember();
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        List<MemberRelationDO> relationDOList = relationRepository.findBySubMemberIdAndRelType(memberUserDO.getMember().getId(), MemberRelationTypeEnum.PLATFORM.getCode());
        if(CollectionUtils.isEmpty(relationDOList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        if(relationDOList.stream().noneMatch(relationDO -> relationDO.getSubRole().getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_CONSUMER.getCode()))) {
            return Wrapper.fail(ResponseCode.MC_MS_MOBILE_USER_HAS_NO_CONSUMER_ROLE);
        }

        if(relationDOList.stream().noneMatch(relationDO -> relationDO.getSubRole().getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_CONSUMER.getCode()) && relationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode()))) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_HAS_BEEN_FROZEN);
        }

        return Wrapper.success();
    }

    /**
     * 检查邮箱是否被注册使用
     *
     * @param emailVO 邮箱
     * @return 检查结果
     */
    @Override
    public Wrapper<Void> checkEmailRegistered(EmailVO emailVO) {
        //查询邮箱是否已经存在
        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()));
            list.add(criteriaBuilder.equal(root.get("email").as(String.class), emailVO.getEmail()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if(memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
        }

        return Wrapper.success();
    }

    /**
     * 发送注册时短信验证码（无滑块验证）
     *
     * @param phoneVO 手机号码
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendRegisterSmsCode(PhoneVO phoneVO) {
        Wrapper<String> phoneResult = checkCountryPhone(phoneVO.getCountryCode(), phoneVO.getPhone(), false);
        if(phoneResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(phoneResult.getCode(), phoneResult.getMessage());
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.MEMBER_REGISTER_SMS_CODE_REDIS_KEY_PREFIX + phoneVO.getPhone();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));
        return smsFeignService.sendRegisterSms(phoneVO.getCountryCode(), phoneResult.getData(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 发送注册时短信验证码
     *
     * @param phoneVO 手机号码
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendRegisterSmsCode(SmsPhoneVO phoneVO) {
        Wrapper<String> phoneResult = checkCountryPhone(phoneVO.getCountryCode(), phoneVO.getPhone(), false);
        if(phoneResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(phoneResult.getCode(), phoneResult.getMessage());
        }

        //校验滑块数据
        Wrapper<Void> captchaResult = checkCaptcha(phoneVO.getImgId(), phoneVO.getWidth());
        if(captchaResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(captchaResult.getCode(), captchaResult.getMessage());
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.MEMBER_REGISTER_SMS_CODE_REDIS_KEY_PREFIX + phoneVO.getPhone();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));
        return smsFeignService.sendRegisterSms(phoneVO.getCountryCode(), phoneResult.getData(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 发送手机号找回密码时的短信验证码
     *
     * @param phoneVO 手机号码
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendResetPasswordSmsCode(SmsPhoneVO phoneVO) {
        Wrapper<String> phoneResult = checkCountryPhone(phoneVO.getCountryCode(), phoneVO.getPhone(), true);
        if(phoneResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(phoneResult.getCode(), phoneResult.getMessage());
        }

        //校验滑块数据
        Wrapper<Void> captchaResult = checkCaptcha(phoneVO.getImgId(), phoneVO.getWidth());
        if(captchaResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(captchaResult.getCode(), captchaResult.getMessage());
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.RESET_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + phoneResult.getData();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendResetPasswordSms(phoneVO.getCountryCode(), phoneResult.getData(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * App - 发送手机号找回密码时的短信验证码
     *
     * @param phoneVO 手机号码
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendMobileResetPasswordSmsCode(PhoneVO phoneVO) {
        Wrapper<String> phoneResult = checkCountryPhone(phoneVO.getCountryCode(), phoneVO.getPhone(), true);
        if(phoneResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(phoneResult.getCode(), phoneResult.getMessage());
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.RESET_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + phoneResult.getData();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendResetPasswordSms(phoneVO.getCountryCode(), phoneResult.getData(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 校验手机号找回密码时的短信验证码是否正确
     *
     * @param phoneSmsVO 手机号码、验证码
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> checkResetPasswordSmsCode(PhoneSmsVO phoneSmsVO) {
        Wrapper<String> phoneResult = checkCountryPhone(phoneSmsVO.getCountryCode(), phoneSmsVO.getPhone(), false);
        if(phoneResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(phoneResult.getCode(), phoneResult.getMessage());
        }

        String cacheKey = ServiceConfig.RESET_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + phoneResult.getData();
        String smsCode = memberCacheService.getString(cacheKey);
        return !StringUtils.hasLength(smsCode) || !smsCode.equals(phoneSmsVO.getSmsCode()) ? Wrapper.fail(ResponseCode.MC_MS_SMS_CODE_EXPIRE_OR_MISMATCH) : Wrapper.success();
    }

    /**
     * 根据短信验证码重设密码
     *
     * @param codeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> resetPasswordBySmsCode(ResetPasswordBySmsCodeVO codeVO) {
        String cacheKey = ServiceConfig.RESET_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + codeVO.getPhone();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!codeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        MemberUserDO userDO = memberUserRepository.findFirstByPhoneAndRelType(codeVO.getPhone(), MemberRelationTypeEnum.OTHER.getCode());
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String newPassword;
        try {
            newPassword = PasswordUtil.instance().decryptAesThenMd5(codeVO.getPassword());
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.BUSINESS_ERROR);
        }

        userDO.setPassword(newPassword);
        memberUserRepository.saveAndFlush(userDO);

        //更改会员的密码
        if(userDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            memberDO.setPassword(newPassword);
            memberRepository.saveAndFlush(memberDO);
        }

        //删除缓存
        memberCacheService.deleteString(cacheKey);

        return Wrapper.success();
    }

    /**
     * 发送邮箱找回密码时的邮件
     *
     * @param fromMobile 是否来自移动客户端（如果是，则要判断有无服务消费者角色）
     * @param emailVO    邮箱地址
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendResetPasswordEmail(EmailVO emailVO, Boolean fromMobile) {
        MemberDO platformMemberDO = memberRepository.findFirstByAccount(ServiceConfig.PLATFORM_SUPER_ADMIN_ACCOUNT);
        if (platformMemberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_CANNOT_REGISTER_BEFORE_PLATFORM_MEMBER_CREATE);
        }

        MemberUserDO userDO = memberUserRepository.findFirstByEmailAndRelType(emailVO.getEmail(), MemberRelationTypeEnum.OTHER.getCode());
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        if(fromMobile && baseMobileService.hasNoConsumerRole(userDO)) {
            return Wrapper.fail(ResponseCode.MC_MS_MOBILE_USER_HAS_NO_CONSUMER_ROLE);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.RESET_PASSWORD_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.MAILCODE_CACHED_TIME_MINUTES * 60));

        String title = "瓴犀B2B平台";
        String content = "【B2B平台】" + smsCode + "，B2B平台动态验证码。工作人员不会向你索要，请勿向任何人泄露。";
        MailUtil.sendTextMail(title, content, userDO.getEmail());

        return Wrapper.success();
    }

    /**
     * 校验发送邮箱找回密码时的邮件中的验证码是否正确
     *
     * @param emailVO 邮箱地址
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> checkResetPasswordEmailCode(EmailSmsVO emailVO) {
        MemberUserDO userDO = memberUserRepository.findFirstByEmailAndRelType(emailVO.getEmail(), MemberRelationTypeEnum.OTHER.getCode());
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_SMS_CODE_EXPIRE_OR_MISMATCH);
        }

        String cacheKey = ServiceConfig.RESET_PASSWORD_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        return !StringUtils.hasLength(smsCode) || !smsCode.equals(emailVO.getSmsCode()) ? Wrapper.fail(ResponseCode.MC_MS_SMS_CODE_EXPIRE_OR_MISMATCH) : Wrapper.success();
    }

    /**
     * 根据邮箱验证码重设密码
     *
     * @param codeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> resetPasswordByEmailCode(ResetPasswordByEmailCodeVO codeVO) {
        MemberDO platformMemberDO = memberRepository.findFirstByAccount(ServiceConfig.PLATFORM_SUPER_ADMIN_ACCOUNT);
        if (platformMemberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_CANNOT_REGISTER_BEFORE_PLATFORM_MEMBER_CREATE);
        }

        MemberUserDO userDO = memberUserRepository.findFirstByMemberNotAndEmail(platformMemberDO, codeVO.getEmail());
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        MemberDO memberDO = userDO.getMember();
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String cacheKey = ServiceConfig.RESET_PASSWORD_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!codeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        String newPassword;
        try {
            newPassword = PasswordUtil.instance().passwordToMd5String(Aes128Util.aesDecrypt(codeVO.getPassword()));
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.BUSINESS_ERROR);
        }

        userDO.setPassword(newPassword);
        memberUserRepository.saveAndFlush(userDO);

        //更改会员的密码
        if(userDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            memberDO.setPassword(newPassword);
            memberRepository.saveAndFlush(memberDO);
        }

        //删除缓存
        memberCacheService.deleteString(cacheKey);

        return Wrapper.success();
    }

    /**
     * 获取会员注册页面-会员类型、商业类型页面内容（第二页）
     * @return 操作结果
     */
    @Override
    public Wrapper<List<MemberRegisterTypeMenuVO>> getRegisterTypePageContent() {
        List<MemberTypeDO> memberTypeDOList = memberTypeRepository.findAll(Sort.by("id").ascending());

        //去掉平台后台的业务类型，以及状态为禁用的角色关联的类型
        List<RoleDO> roleDOList = roleRepository.findAll().stream().filter(roleDO -> !roleDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode()) && roleDO.getStatus().equals(EnableDisableStatus.ENABLE.getCode())).collect(Collectors.toList());
        List<MemberRegisterTypeMenuVO> resultList = memberTypeDOList.stream().map(memberTypeDO -> {
            MemberRegisterTypeMenuVO menuVO = new MemberRegisterTypeMenuVO();
            menuVO.setMemberTypeId(memberTypeDO.getId());
            menuVO.setMemberTypeName(MemberTypeEnum.getCodeMessage(memberTypeDO.getTypeEnum()));

            List<MemberRegisterTypeMenuVO.InnerBusinessType> businessTypeList = roleDOList.stream().filter(roleDO -> roleDO.getMemberType().getId().equals(memberTypeDO.getId())).map(roleDO -> {
                MemberRegisterTypeMenuVO.InnerBusinessType innerBusinessType = new MemberRegisterTypeMenuVO.InnerBusinessType();
                innerBusinessType.setBusinessTypeId(roleDO.getBusinessType().getId());
                innerBusinessType.setBusinessTypeName(roleDO.getBusinessType().getBusinessTypeName());
                return innerBusinessType;
            }).collect(Collectors.toList());
            menuVO.setBusinessTypes(businessTypeList);
            return menuVO;
        }).collect(Collectors.toList());

        return Wrapper.success(resultList);
    }

    /**
     * 获取App客户端会员注册页面-会员类型、商业类型页面内容（第二页）
     *
     * @return 操作结果
     */
    @Override
    public Wrapper<List<MemberRegisterTypeMenuVO>> getMobileRegisterTypePageContent() {
        List<RoleDO> roleDOList = roleRepository.findAll().stream().filter(roleDO -> !roleDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode()) && roleDO.getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_CONSUMER.getCode()) && roleDO.getStatus().equals(EnableDisableStatus.ENABLE.getCode())).collect(Collectors.toList());
        List<MemberRegisterTypeMenuVO> typeMenuVOList = new ArrayList<>();
        for (RoleDO roleDO : roleDOList) {
            MemberRegisterTypeMenuVO typeMenuVO = typeMenuVOList.stream().filter(vo -> vo.getMemberTypeId().equals(roleDO.getMemberType().getId())).findFirst().orElse(null);
            if(typeMenuVO == null) {
                typeMenuVO = new MemberRegisterTypeMenuVO();
                typeMenuVO.setMemberTypeId(roleDO.getMemberType().getId());
                typeMenuVO.setMemberTypeName(MemberTypeEnum.getCodeMessage(roleDO.getMemberType().getTypeEnum()));
                List<MemberRegisterTypeMenuVO.InnerBusinessType> innerBusinessTypes = new ArrayList<>();
                MemberRegisterTypeMenuVO.InnerBusinessType businessType = new MemberRegisterTypeMenuVO.InnerBusinessType();
                businessType.setBusinessTypeId(roleDO.getBusinessType().getId());
                businessType.setBusinessTypeName(roleDO.getBusinessType().getBusinessTypeName());
                innerBusinessTypes.add(businessType);
                typeMenuVO.setBusinessTypes(innerBusinessTypes);

                typeMenuVOList.add(typeMenuVO);
            } else {
                if(typeMenuVO.getBusinessTypes().stream().noneMatch(innerBusinessType -> innerBusinessType.getBusinessTypeId().equals(roleDO.getBusinessType().getId()))) {
                    MemberRegisterTypeMenuVO.InnerBusinessType businessType = new MemberRegisterTypeMenuVO.InnerBusinessType();
                    businessType.setBusinessTypeId(roleDO.getBusinessType().getId());
                    businessType.setBusinessTypeName(roleDO.getBusinessType().getBusinessTypeName());
                    typeMenuVO.getBusinessTypes().add(businessType);
                    typeMenuVO.getBusinessTypes().sort(Comparator.comparingLong(MemberRegisterTypeMenuVO.InnerBusinessType::getBusinessTypeId));
                }
            }
        }

        typeMenuVOList.sort(Comparator.comparingLong(MemberRegisterTypeMenuVO::getMemberTypeId));
        return Wrapper.success(typeMenuVOList);
    }

    /**
     * 获取会员注册页面-详细信息页面内容（第三页）
     * @param detailVO 接口参数
     * @return 注册第三页的内容
     */
    @Override
    public Wrapper<List<MemberConfigGroupVO>> getRegisterDetailPageContent(MemberDetailVO detailVO) {
        MemberTypeDO memberTypeDO = memberTypeRepository.findById(detailVO.getMemberTypeId()).orElse(null);
        if(memberTypeDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_TYPE_DOES_NOT_EXIST);
        }

        MemberBusinessTypeDO businessTypeDO = memberBusinessTypeRepository.findById(detailVO.getBusinessTypeId()).orElse(null);
        if(businessTypeDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_BUSINESS_TYPE_DOES_NOT_EXIST);
        }

        RoleDO roleDO = roleRepository.findFirstByBusinessTypeAndMemberTypeAndRelTypeNotAndStatus(businessTypeDO, memberTypeDO, MemberRelationTypeEnum.PLATFORM.getCode(), EnableDisableStatus.ENABLE.getCode());
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        return Wrapper.success(baseMemberRegisterDetailService.groupMemberConfig(new ArrayList<>(roleDO.getConfigs())));
    }

    /**
     * 平台会员注册
     * @param registerSourceEnum 注册来源枚举
     * @param smsCode  短信验证码
     * @param countryCode 国家代码
     * @param phone 手机号码
     * @param userPassword 用户密码（Aes加密后的密码）
     * @param email 邮箱
     * @param memberTypeId 会员类型Id
     * @param businessTypeId 业务类型Id
     * @param detail 注册资料
     * @return 注册结果
     */
    @Override
    public Wrapper<MemberRegisterResultVO> registerPlatformMember(MemberRegisterSourceEnum registerSourceEnum, String smsCode, String countryCode, String phone, String userPassword, String email, Long memberTypeId, Long businessTypeId, Map<String, Object> detail) {
        //todo 正式上线放开注释
//        String cacheKey = ServiceConfig.MEMBER_REGISTER_SMSCODE_REDIS_KEY_PREFIX + phone;
//        String cacheCode = memberCacheService.getString(cacheKey);
//        if(!StringUtils.hasLength(cacheCode)) {
//            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
//        }
//
//        if(!smsCode.equals(cacheCode)) {
//            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
//        }

        //幂等校验：判断手机号和邮箱是否存在
        if(memberCacheService.existRegisterKey(phone, false)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_ACCOUNT_OR_PHONE_EXISTS);
        }

        if(StringUtils.hasLength(email) && memberCacheService.existRegisterKey(email, false)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
        }

        memberCacheService.setRegisterKey(phone, email, false);

        //查询平台会员和平台角色
        MemberDO platformMemberDO = memberRepository.findFirstByAccount(ServiceConfig.PLATFORM_SUPER_ADMIN_ACCOUNT);
        if (platformMemberDO == null) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(ResponseCode.MC_MS_CANNOT_REGISTER_BEFORE_PLATFORM_MEMBER_CREATE);
        }

        RoleDO platformRoleDO = platformMemberDO.getRoles().stream().filter(r -> r.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())).findFirst().orElse(null);
        if (platformRoleDO == null) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(ResponseCode.MC_MS_CANNOT_REGISTER_BEFORE_PLATFORM_MEMBER_CREATE);
        }

        //检查手机号是否已经存在
        if(memberUserRepository.existsByRelTypeAndPhone(MemberRelationTypeEnum.OTHER.getCode(), phone)) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_EXISTS);
        }

        //判断邮箱（如果非空）是否存在
        if(StringUtils.hasLength(email) && memberUserRepository.existsByRelTypeAndEmail(MemberRelationTypeEnum.OTHER.getCode(), email)) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
        }

        MemberTypeDO memberTypeDO = memberTypeRepository.findById(memberTypeId).orElse(null);
        if (memberTypeDO == null) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_TYPE_DOES_NOT_EXIST);
        }

        MemberBusinessTypeDO memberBusinessTypeDO = memberBusinessTypeRepository.findById(businessTypeId).orElse(null);
        if (memberBusinessTypeDO == null) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_BUSINESS_TYPE_DOES_NOT_EXIST);
        }

        //通过会员类型、业务类型查找角色
        RoleDO roleDO = roleRepository.findFirstByBusinessTypeAndMemberTypeAndRelTypeNotAndStatus(memberBusinessTypeDO, memberTypeDO, MemberRelationTypeEnum.PLATFORM.getCode(), EnableDisableStatus.ENABLE.getCode());
        if (roleDO == null) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        //检查注册信息
        List<MemberRegisterDetailDO> memberRegisterDetails = new ArrayList<>();
        Wrapper<String> checkResult = baseMemberRegisterDetailService.checkMemberRegisterDetail(detail, new ArrayList<>(roleDO.getConfigs()), memberRegisterDetails, phone);
        if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
        }

        //会员名称和详细信息
        String memberName = checkResult.getData();
        if(StringUtils.hasLength(memberName) && memberRepository.existsByName(memberName)) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_NAME_REGISTERED);
        }

        String md5Password;
        try {
            md5Password = PasswordUtil.instance().decryptAesThenMd5(userPassword);
        } catch (Exception e) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(ResponseCode.AES_DECRYPTION_ERROR);
        }

        //根据角色查找平台会员审核流程的Key
        Wrapper<ProcessBO> processResult = basePlatformProcessService.findRolePlatformProcess(roleDO);
        if(processResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(processResult.getCode(), processResult.getMessage());
        }

        //该会员角色是否配置的是无需审核的工作流
        Boolean verify = processResult.getData().getEmptyProcess();

        //新增会员
        AddMemberBO memberBO = new AddMemberBO();
        memberBO.setPlatformProcess(processResult.getData());
        memberBO.setUpperMember(platformMemberDO);
        memberBO.setUpperRole(platformRoleDO);
        memberBO.setRoleDO(roleDO);
        memberBO.setMemberTypeDO(memberTypeDO);
        memberBO.setBusinessTypeDO(memberBusinessTypeDO);
        memberBO.setRegisterDetails(memberRegisterDetails);
        memberBO.setName(memberName);
        memberBO.setCountryCode(countryCode);
        memberBO.setPhone(phone);
        //通过注册页面的手机号即账号
        memberBO.setAccount(phone);
        memberBO.setPassword(md5Password);
        memberBO.setEmail(StringUtils.hasLength(email) ? email.trim() : "");
        //注册来源
        memberBO.setSource(registerSourceEnum);
        //会员注册，其外部审核记录的操作角色为会员角色
        memberBO.setOperatorRoleName(roleDO.getRoleName());
        memberBO.setInnerStatus(PlatformInnerStatusEnum.TO_BE_COMMIT.getCode());
        //设置等级为Null，自动查询最小等级
        memberBO.setLevel(null);

        Wrapper<?> result = memberInnerService.addPlatformMember(memberBO);
        if (result.getCode() != ResponseCode.SUCCESS.getCode()) {
            memberCacheService.deleteRegisterKey(phone, email, false);
            return Wrapper.fail(result.getCode(), result.getMessage());
        }

        return Wrapper.success(new MemberRegisterResultVO(verify));
    }

    /**
     * 校验国家代码、手机号码
     * @param countryCode 国家代码
     * @param aesEncryptPhone AES加密后的手机号码
     * @param checkPhoneExist 是否检查手机号是否已经注册
     * @return 解密后的手机号码
     */
    private Wrapper<String> checkCountryPhone(String countryCode, String aesEncryptPhone, boolean checkPhoneExist) {
        CountryCodeEnum countryCodeEnum = CountryCodeEnum.findByCode(countryCode);
        if(countryCodeEnum == null) {
            return Wrapper.fail(ResponseCode.MC_MS_COUNTRY_CODE_DOES_NOT_EXIST);
        }

        String phone = Aes128Util.tryAesDecrypt(aesEncryptPhone);
        if(!StringUtils.hasLength(phone) || !SecurityStringUtils.checkPhone(countryCodeEnum, phone)) {
            return Wrapper.fail(ResponseCode.MC_MS_PHONE_FORMAT_INCORRECT);
        }

        if(checkPhoneExist && !memberUserRepository.existsByRelTypeAndPhone(MemberRelationTypeEnum.OTHER.getCode(), phone)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        return Wrapper.success(phone);
    }

    /**
     * 验证滑块
     * @param imgId 滑块Id
     * @param width 滑块宽度
     * @return 校验结果
     */
    private Wrapper<Void> checkCaptcha(String imgId, Double width) {
        String widthCache = (String) redisUtils.get(ServiceConfig.MEMBER_REGISTER_CAPTCHA_IMG_REDIS_KEY_PREFIX + imgId, Constants.REDIS_USER_INDEX);
        if(!StringUtils.hasLength(widthCache)) {
            return Wrapper.fail(ResponseCode.MC_MS_CAPTCHA_EXPIRED);
        }

        double xWidth = new Double(widthCache) - width;
        if(!(xWidth >= -5 && xWidth <= 5)) {
            return Wrapper.fail(ResponseCode.MC_MS_CAPTCHA_MISMATCHED);
        }

        redisUtils.del(ServiceConfig.MEMBER_REGISTER_CAPTCHA_IMG_REDIS_KEY_PREFIX + imgId, Constants.REDIS_USER_INDEX);
        return Wrapper.success();
    }
}
